#ifndef OOPSMP_UTILS_GENERAL_BBOX_BV_GENERIC_H_
#define OOPSMP_UTILS_GENERAL_BBOX_BV_GENERIC_H_

#include <vector>
#include "OOPSMP/Utils/Math/Algebra/vector3.h"
#include "OOPSMP/Utils/Math/Algebra/matrix44.h"
#include "OOPSMP/Utils/Geometry/Workspace/Part.H"

namespace OOPSMP {
	
	/**
	 *@brief Macro for class, class pointer, and const class pointer
	 *       declarations 
	 */
	ForwardClassDeclaration(BVGeneric);
	
	/**
	 *@brief bv generic
	 */
	class BVGeneric {

	protected:
		
		/**
		 *@brief bounding box as std::vector
		 */
		std::vector<double> bbox;

	public:

		/**
		 *@brief Default constructor
		 */
		BVGeneric()/* : n_elements( 0 )*/ { }

		/**
		 *@brief Constructor with number of elements in box
		 *@param size number of elements
		 */
		BVGeneric( long size )/* : n_elements( size )*/ { }

		/**
		 *@brief Constructor with bounding box as vector
		 *@param box bbox vector
		 */
		BVGeneric( std::vector<double> box ) : bbox( box )/*, n_elements( box.size() )*/ { }

		/**
		 *@brief Constructor with bounding box as array of doubles
		 *@param box bbox array
		 *@param size array length
		 */
		BVGeneric( double * box, long size ) {
			/*n_elements = size;*/
			bbox.resize( size );
			for ( int i = 0 ; i < size ; i++ )
				bbox.push_back( box[i] );
		}

		/**
		 *@brief Default destructor
		 */
		~BVGeneric() { }

		/**
		 *@brief Returns number of elements in bounding box array
		 */
		virtual long getNumElements() { return 0; }

		/**
		 *@brief Returns bounding box as vector
		 */
		std::vector<double> getBBoxAsVector() { return bbox; }

		/**
		 *@brief Returns bounding box as array of doubles
		 *@params tmp empty array to contain bounding box
		 */
		void getBBoxAsArray( double * tmp ) {

			// double * tmp = new double[getNumElements()];
			long index = 0;

			for( std::vector<double>::iterator iter = bbox.begin() ; iter < bbox.end() ; iter++ )
				tmp[index++] = *iter;

		}

		/**
		 *@brief Sets bounding box to the provided array of doubles
		 *@params box array describing bounding box
		 */
		void setBoundingBoxToArray( const double * box ) {

			// assuming the box contains n_elements doubles
			for ( long i = 0 ; i < getNumElements() ; i++ )
				bbox.push_back( box[i] );

		}

		/**
		 *@brief Virtual function, must be overidden in deriving class
		 */
		virtual void calculateBoundingBox( const double * m_vertices, const long n_vertices ) = 0;

		/**
		 *@brief Virtual function, must be overidden in deriving class
		 */
		virtual void calculateBoundingBox( const double * m_vertices, const long n_vertices, const double * trans, double * out ) = 0;

		/**
		 *@brief Virtual function, must be overidden in deriving class
		 */
		virtual void calculateBoundingBox( Part_const_t part ) = 0;

		/**
		 *@brief Virtual function, must be overidden in deriving class
		 */
		virtual void calculateBoundingBox( Part_const_t part, double * out ) = 0;

		/**
		 *@brief Virtual function, must be overidden in deriving class
		 */
		virtual void getBBoxDimensions(double * linkDims) const = 0;

	};
	/**
     *@brief Declare factory and specify in source file the functions that should
     *       be registered for plug-and-play functionality
     */ 
	DeclareNoInstanceFactory(BVGeneric, Factory);

}

#endif